/*!
 * Column visibility buttons for Buttons and DataTables.
 * 2016 SpryMedia Ltd - datatables.net/license
 */

(function (factory) {
  if (typeof define === 'function' && define.amd) {
    // AMD
    define(['jquery', 'datatables.net', 'datatables.net-buttons'], function ($) {
      return factory($, window, document);
    });
  } else if (typeof exports === 'object') {
    // CommonJS
    module.exports = function (root, $) {
      if (!root) {
        root = window;
      }

      if (!$ || !$.fn.dataTable) {
        $ = require('datatables.net')(root, $).$;
      }

      if (!$.fn.dataTable.Buttons) {
        require('datatables.net-buttons')(root, $);
      }

      return factory($, root, root.document);
    };
  } else {
    // Browser
    factory(jQuery, window, document);
  }
}(function ($, window, document, undefined) {
  'use strict';
  var DataTable = $.fn.dataTable;


  $.extend(DataTable.ext.buttons, {
    // A collection of column visibility buttons
    colvis: function (dt, conf) {
      return {
        extend: 'collection',
        text: function (dt) {
          return dt.i18n('buttons.colvis', 'Column visibility');
        },
        className: 'buttons-colvis',
        buttons: [{
          extend: 'columnsToggle',
          columns: conf.columns,
          columnText: conf.columnText
        }]
      };
    },

    // Selected columns with individual buttons - toggle column visibility
    columnsToggle: function (dt, conf) {
      var columns = dt.columns(conf.columns).indexes().map(function (idx) {
        return {
          extend: 'columnToggle',
          columns: idx,
          columnText: conf.columnText
        };
      }).toArray();

      return columns;
    },

    // Single button to toggle column visibility
    columnToggle: function (dt, conf) {
      return {
        extend: 'columnVisibility',
        columns: conf.columns,
        columnText: conf.columnText
      };
    },

    // Selected columns with individual buttons - set column visibility
    columnsVisibility: function (dt, conf) {
      var columns = dt.columns(conf.columns).indexes().map(function (idx) {
        return {
          extend: 'columnVisibility',
          columns: idx,
          visibility: conf.visibility,
          columnText: conf.columnText
        };
      }).toArray();

      return columns;
    },

    // Single button to set column visibility
    columnVisibility: {
      columns: undefined, // column selector
      text: function (dt, button, conf) {
        return conf._columnText(dt, conf);
      },
      className: 'buttons-columnVisibility',
      action: function (e, dt, button, conf) {
        var col = dt.columns(conf.columns);
        var curr = col.visible();

        col.visible(conf.visibility !== undefined ?
          conf.visibility :
          !(curr.length ? curr[0] : false)
        );
      },
      init: function (dt, button, conf) {
        var that = this;
        button.attr('data-cv-idx', conf.columns);

        dt
          .on('column-visibility.dt' + conf.namespace, function (e, settings) {
            if (!settings.bDestroying && settings.nTable == dt.settings()[0].nTable) {
              that.active(dt.column(conf.columns).visible());
            }
          })
          .on('column-reorder.dt' + conf.namespace, function (e, settings, details) {
            if (dt.columns(conf.columns).count() !== 1) {
              return;
            }

            // This button controls the same column index but the text for the column has
            // changed
            that.text(conf._columnText(dt, conf));

            // Since its a different column, we need to check its visibility
            that.active(dt.column(conf.columns).visible());
          });

        this.active(dt.column(conf.columns).visible());
      },
      destroy: function (dt, button, conf) {
        dt
          .off('column-visibility.dt' + conf.namespace)
          .off('column-reorder.dt' + conf.namespace);
      },

      _columnText: function (dt, conf) {
        // Use DataTables' internal data structure until this is presented
        // is a public API. The other option is to use
        // `$( column(col).node() ).text()` but the node might not have been
        // populated when Buttons is constructed.
        var idx = dt.column(conf.columns).index();
        var title = dt.settings()[0].aoColumns[idx].sTitle;

        if (!title) {
          title = dt.column(idx).header().innerHTML;
        }

        title = title
          .replace(/\n/g, " ")        // remove new lines
          .replace(/<br\s*\/?>/gi, " ")  // replace line breaks with spaces
          .replace(/<select(.*?)<\/select>/g, "") // remove select tags, including options text
          .replace(/<!\-\-.*?\-\->/g, "") // strip HTML comments
          .replace(/<.*?>/g, "")   // strip HTML
          .replace(/^\s+|\s+$/g, ""); // trim

        return conf.columnText ?
          conf.columnText(dt, idx, title) :
          title;
      }
    },


    colvisRestore: {
      className: 'buttons-colvisRestore',

      text: function (dt) {
        return dt.i18n('buttons.colvisRestore', 'Restore visibility');
      },

      init: function (dt, button, conf) {
        conf._visOriginal = dt.columns().indexes().map(function (idx) {
          return dt.column(idx).visible();
        }).toArray();
      },

      action: function (e, dt, button, conf) {
        dt.columns().every(function (i) {
          // Take into account that ColReorder might have disrupted our
          // indexes
          var idx = dt.colReorder && dt.colReorder.transpose ?
            dt.colReorder.transpose(i, 'toOriginal') :
            i;

          this.visible(conf._visOriginal[idx]);
        });
      }
    },


    colvisGroup: {
      className: 'buttons-colvisGroup',

      action: function (e, dt, button, conf) {
        dt.columns(conf.show).visible(true, false);
        dt.columns(conf.hide).visible(false, false);

        dt.columns.adjust();
      },

      show: [],

      hide: []
    }
  });


  return DataTable.Buttons;
}));
